package com.iscas.imchat.sso;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.gson.Gson;
import com.iscas.imchat.utils.Util;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * Author: zhd
 * Data: 2022/6/2
 */
public class TokenAuthenticateHandler extends SimpleChannelInboundHandler<String> {

    private static final String Secret = "iscas_isrc_IM";

    private Util tokenUtil;

    public TokenAuthenticateHandler(Util tokenUtility){
        this.tokenUtil = tokenUtility;
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 获取当前channel
        Channel channel = ctx.channel();
        TokenReqMessage returnMsg;

        // Read class
        Gson gson = new Gson();
        TokenReqMessage message = gson.fromJson(msg,TokenReqMessage.class);

        // 验证token
        if(message.getRequestType() == 1){
            System.out.println("接收到验证Token消息");

            String loginUid = message.getUid();
            String token = message.getToken();
            List<HashMap<String, Object>> userList = this.tokenUtil.Select("select * from token where uid='" + loginUid + " ' and token = '"+token+"';");

            String output;

            if(userList.size() != 0){   //token有效
                try {
                    // 解析Token
                    Algorithm algorithm = Algorithm.HMAC256(Secret);
                    JWTVerifier verifier = JWT.require(algorithm)
                            .withIssuer("auth0")
                            .build(); //Reusable verifier instance
                    DecodedJWT jwt = verifier.verify(token);
                    // 过期日
                    Date expiresAt  = jwt.getExpiresAt();
                    // 7天后
                    Calendar nowTime = Calendar.getInstance();
                    nowTime.add(Calendar.DATE, 7);
                    Date sevenDaysLater = nowTime.getTime();

                    // 是否过期
                    if(new Date().after(expiresAt)){    // 未过期
                        // *********返回token验证成功 1
                        returnMsg = new TokenReqMessage(2, loginUid,"", "", 1);
                        output = new Gson().toJson(returnMsg);
                    }else if(sevenDaysLater.after(expiresAt)){ //未过期但距离过期不足7天，更新token
                        String newToken = TokenGenerateHandler.genTokenFromUid(loginUid);
                        tokenUtil.Update("update token set token = '"+newToken+"' where uid = '"+loginUid+"';");
                        // 返回token验证成功且更新 2
                        returnMsg = new TokenReqMessage(2, loginUid,"", newToken, 2);
                        output = new Gson().toJson(returnMsg);
                    }else{  // 过期需要重新登陆
                        // 删除token缓存
                        tokenUtil.Delete("delete from token where uid= '"+loginUid+"';");
                        // 返回token过期需要重新登陆 3
                        returnMsg = new TokenReqMessage(2, loginUid,"", "", 3);
                        output = new Gson().toJson(returnMsg);
                    }

                } catch (JWTVerificationException exception){
                    System.out.println("Invalid signature/claims");
                    returnMsg = new TokenReqMessage(2, loginUid,"", "", 3);
                    output = new Gson().toJson(returnMsg);
                }
            }else { // token无效
                System.out.println("token表中不存在此uid或token");
                // *********发送客户端需要重新登录 3
                returnMsg = new TokenReqMessage(2, loginUid,"", "", 3);
                output = new Gson().toJson(returnMsg);
            }
        channel.writeAndFlush(output);

        }else{
            System.out.println("验证Token消息不合法");
        }
        // 当前channel返回信息
        channel.close();

    }


}
